To simplify the following discussion, the present invention will be explained in terms of programs for translating code from one computer to a computer with a different instruction set. However, as explained below, the present invention may be utilized in a wider range of translation and optimization problems.
The cost of translating code from one computer to a computer having a different instruction set is considerable, if not prohibitive in many instances. In some cases, the original source code is not available to the user, and hence, recompilation of the old program into instructions of the new computer is not an option. Even when the source code is available, the labor needed to adapt the code to the new architecture can require a substantial effort over an extended period of time. During this time, the user must still be able to run the old programs.
Accordingly, developers of new computers often provide emulators which allow code written in the old instruction set to be run on the new computer. In general, there is not a one-to-one correspondence between the instruction in the old instruction set and those in the new instruction set. Hence, the emulator often translates an instruction in the original code into a plurality of instructions in the new instruction set.
In addition, the hardware in the new computer may differ substantially from that in the old computer. For example, the number of registers and the length of these registers may differ between the two machines. Hence, the emulator must also provide a "virtual" machine that duplicates the old machine. For example, if the old computer system provided a response to an event which resulted in a dump of the registers being generated, the emulator must generate a dump of the contents of the virtual machine from the contents of the new computer.
Such dumps are often associated with asynchronous exceptions or events. In the old hardware, the event is assumed to occur between two instructions, since most exceptions allow an instruction in progress to be completed. The dump then represents the state of the system at the end of the instruction that has just been completed. If the code has indicated that the user is providing an event handler for the particular type of event that occurred, the dump is forwarded to the event handler when the hardware detects the event. The handler assumes that the dump represents the state of the system at the end of the last instruction encountered in the old code.
The emulation of asynchronous events is complicated by the lick of a one-to-one mapping between the old and new instruction sets. Consider the case of an instruction in the old code set that is mapped into 3 instructions in the new instruction set. If an event occurs between the first and second instruction in the emulation, the state of the virtual machine is not well defined, since the virtual machine is still in the middle of the execution of an instruction in the old instruction set. Hence, the event must be "stored" until the end of the third instruction. At that time, the state of the virtual machine is known and the event can be sent to the appropriate handler with a dump of the virtual machine.
One method for accommodating asynchronous events is to insert code at the end of each block of instructions to test for the occurrence of such an event. While this assures that the virtual machine is in a known state, the overhead involved in this approach is considerable. Asynchronous events are rare. Hence, the event checking code seldom finds an event while requiring the execution of an instruction between each instruction in the original code.
To reduce this overhead, prior art systems make use of the observation that by nature, asynchronous events are not predictable. Accordingly, the handlers provided in the old computer code cannot depend on the exact instruction at which the event occurred. As a result, it is sufficient to check for the occurrence of an event at more widely separated points in the original code. While this approach reduces the overhead discussed above, the overhead remains substantial. For example, if the event check is performed at each backward branch in the code, then an instruction must be inserted at each potential branch. This instruction is executed each time the branch is taken, whether or not an event has occurred.
Broadly, it is the object of the present invention to provide an improved method for handling asynchronous events in an emulation system.
It is a further object of the present invention to provide a method for handling asynchronous events in an emulation system that imposes less overhead than prior methods.
These and other objects of the present invention will become apparent to those skilled in the art from the following detailed description of the invention and the accompanying drawings.